/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.dolphinscheduler.api.controller.process;

import static org.apache.dolphinscheduler.api.enums.Status.BATCH_COPY_PROCESS_DEFINITION_ERROR;
import static org.apache.dolphinscheduler.api.enums.Status.BATCH_DELETE_PROCESS_DEFINE_BY_CODES_ERROR;
import static org.apache.dolphinscheduler.api.enums.Status.BATCH_MOVE_PROCESS_DEFINITION_ERROR;
import static org.apache.dolphinscheduler.api.enums.Status.CREATE_PROCESS_DEFINITION_ERROR;
import static org.apache.dolphinscheduler.api.enums.Status.DELETE_PROCESS_DEFINE_BY_CODE_ERROR;
import static org.apache.dolphinscheduler.api.enums.Status.DELETE_PROCESS_DEFINITION_VERSION_ERROR;
import static org.apache.dolphinscheduler.api.enums.Status.ENCAPSULATION_TREEVIEW_STRUCTURE_ERROR;
import static org.apache.dolphinscheduler.api.enums.Status.GET_TASKS_LIST_BY_PROCESS_DEFINITION_ID_ERROR;
import static org.apache.dolphinscheduler.api.enums.Status.IMPORT_PROCESS_DEFINE_ERROR;
import static org.apache.dolphinscheduler.api.enums.Status.QUERY_DETAIL_OF_PROCESS_DEFINITION_ERROR;
import static org.apache.dolphinscheduler.api.enums.Status.QUERY_PROCESS_DEFINITION_ALL_VARIABLES_ERROR;
import static org.apache.dolphinscheduler.api.enums.Status.QUERY_PROCESS_DEFINITION_LIST;
import static org.apache.dolphinscheduler.api.enums.Status.QUERY_PROCESS_DEFINITION_LIST_PAGING_ERROR;
import static org.apache.dolphinscheduler.api.enums.Status.QUERY_PROCESS_DEFINITION_VERSIONS_ERROR;
import static org.apache.dolphinscheduler.api.enums.Status.RELEASE_PROCESS_DEFINITION_ERROR;
import static org.apache.dolphinscheduler.api.enums.Status.SWITCH_PROCESS_DEFINITION_VERSION_ERROR;
import static org.apache.dolphinscheduler.api.enums.Status.UPDATE_PROCESS_DEFINITION_ERROR;
import static org.apache.dolphinscheduler.api.enums.Status.VERIFY_PROCESS_DEFINITION_NAME_UNIQUE_ERROR;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.media.Schema;
import org.apache.dolphinscheduler.api.aspect.AccessLogAnnotation;
import org.apache.dolphinscheduler.api.controller.BaseController;
import org.apache.dolphinscheduler.api.enums.Status;
import org.apache.dolphinscheduler.api.exceptions.ApiException;
import org.apache.dolphinscheduler.api.service.ProcessDefinitionService;
import org.apache.dolphinscheduler.api.utils.PageInfo;
import org.apache.dolphinscheduler.api.utils.Result;
import org.apache.dolphinscheduler.common.constants.Constants;
import org.apache.dolphinscheduler.common.enums.ProcessExecutionTypeEnum;
import org.apache.dolphinscheduler.common.enums.ReleaseState;
import org.apache.dolphinscheduler.plugin.task.api.utils.ParameterUtils;
import org.apache.dolphinscheduler.dao.entity.ProcessDefinition;
import org.apache.dolphinscheduler.dao.entity.User;

import springfox.documentation.annotations.ApiIgnore;

import org.apache.commons.lang3.StringUtils;

import java.text.MessageFormat;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;

/**
 * process definition controller
 */
@Api(tags = "PROCESS_DEFINITION_TAG")
@RestController
@RequestMapping("projects/{projectCode}/process-definition")
public class ProcessDefinitionController extends BaseController {

  private static final Logger logger = LoggerFactory.getLogger(ProcessDefinitionController.class);

  @Autowired
  private ProcessDefinitionService processDefinitionService;

  /**
   * 创建流程定义
   *
   * @param loginUser          login user
   * @param projectCode        project code
   * @param name               process definition name
   * @param description        description
   * @param globalParams       globalParams
   * @param locations          locations for nodes
   * @param timeout            timeout
   * @param tenantCode         tenantCode
   * @param taskRelationJson   relation json for nodes
   * @param taskDefinitionJson taskDefinitionJson
   * @param otherParamsJson    otherParamsJson handle other params
   * @return create result code
   */
  @ApiOperation(value = "createProcessDefinition", notes = "CREATE_PROCESS_DEFINITION_NOTES")
  @ApiImplicitParams({
      @ApiImplicitParam(name = "name", value = "PROCESS_DEFINITION_NAME", required = true, dataTypeClass = String.class),
      @ApiImplicitParam(name = "locations", value = "PROCESS_DEFINITION_LOCATIONS", required = true, dataTypeClass = String.class),
      @ApiImplicitParam(name = "description", value = "PROCESS_DEFINITION_DESC", required = false, dataTypeClass = String.class),
      @ApiImplicitParam(name = "otherParamsJson", value = "OTHER_PARAMS_JSON", required = false, dataTypeClass = String.class)
  })
  @PostMapping()
  @ResponseStatus(HttpStatus.CREATED)
  @ApiException(CREATE_PROCESS_DEFINITION_ERROR)
  @AccessLogAnnotation(ignoreRequestArgs = "loginUser")
  public Result createProcessDefinition(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
                                        @ApiParam(name = "projectCode", value = "PROJECT_CODE", required = true) @PathVariable long projectCode,
                                        @RequestParam(value = "name", required = true) String name,
                                        @RequestParam(value = "description", required = false) String description,
                                        @RequestParam(value = "globalParams", required = false, defaultValue = "[]") String globalParams,
                                        @RequestParam(value = "locations", required = false) String locations,
                                        @RequestParam(value = "timeout", required = false, defaultValue = "0") int timeout,
                                        @RequestParam(value = "tenantCode", required = true) String tenantCode,
                                        @RequestParam(value = "taskRelationJson", required = true) String taskRelationJson,
                                        @RequestParam(value = "taskDefinitionJson", required = true) String taskDefinitionJson,
                                        @RequestParam(value = "otherParamsJson", required = false) String otherParamsJson,
                                        @RequestParam(value = "executionType", defaultValue = "PARALLEL") ProcessExecutionTypeEnum executionType) {
    Map<String, Object> result = processDefinitionService.createProcessDefinition(loginUser, projectCode, name,
        description, globalParams,
        locations, timeout, tenantCode, taskRelationJson, taskDefinitionJson, otherParamsJson, executionType);
    return returnDataList(result);
  }

  /**
   * copy process definition
   * 复制流程到另外的项目
   *
   * @param loginUser         login user
   * @param projectCode       project code
   * @param codes             process definition codes
   * @param targetProjectCode target project code
   * @return copy result code
   */
  @ApiOperation(value = "batchCopyByCodes", notes = "COPY_PROCESS_DEFINITION_NOTES")
  @ApiImplicitParams({
      @ApiImplicitParam(name = "codes", value = "PROCESS_DEFINITION_CODES", required = true, dataTypeClass = String.class, example = "3,4"),
      @ApiImplicitParam(name = "targetProjectCode", value = "TARGET_PROJECT_CODE", required = true, dataTypeClass = long.class, example = "123")
  })
  @PostMapping(value = "/batch-copy")
  @ResponseStatus(HttpStatus.OK)
  @ApiException(BATCH_COPY_PROCESS_DEFINITION_ERROR)
  @AccessLogAnnotation(ignoreRequestArgs = "loginUser")
  public Result copyProcessDefinition(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
                                      @ApiParam(name = "projectCode", value = "PROJECT_CODE", required = true) @PathVariable long projectCode,
                                      @RequestParam(value = "codes", required = true) String codes,
                                      @RequestParam(value = "targetProjectCode", required = true) long targetProjectCode) {
    return returnDataList(
        processDefinitionService.batchCopyProcessDefinition(loginUser, projectCode, codes, targetProjectCode));
  }

  /**
   * move process definition
   * 移动流程到另外的项目，和复制一样
   *
   * @param loginUser         login user
   * @param projectCode       project code
   * @param codes             process definition codes
   * @param targetProjectCode target project code
   * @return move result code
   */
  @ApiOperation(value = "batchMoveByCodes", notes = "MOVE_PROCESS_DEFINITION_NOTES")
  @ApiImplicitParams({
      @ApiImplicitParam(name = "codes", value = "PROCESS_DEFINITION_CODES", required = true, dataTypeClass = String.class, example = "3,4"),
      @ApiImplicitParam(name = "targetProjectCode", value = "TARGET_PROJECT_CODE", required = true, dataTypeClass = long.class, example = "123")
  })
  @PostMapping(value = "/batch-move")
  @ResponseStatus(HttpStatus.OK)
  @ApiException(BATCH_MOVE_PROCESS_DEFINITION_ERROR)
  @AccessLogAnnotation(ignoreRequestArgs = "loginUser")
  public Result moveProcessDefinition(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
                                      @ApiParam(name = "projectCode", value = "PROJECT_CODE", required = true) @PathVariable long projectCode,
                                      @RequestParam(value = "codes", required = true) String codes,
                                      @RequestParam(value = "targetProjectCode", required = true) long targetProjectCode) {
    return returnDataList(
        processDefinitionService.batchMoveProcessDefinition(loginUser, projectCode, codes, targetProjectCode));
  }

  /**
   * verify process definition name unique
   * 统一项目下面流程名称不能重复
   *
   * @param loginUser   login user
   * @param projectCode project code
   * @param name        name
   * @return true if process definition name not exists, otherwise false
   */
  @ApiOperation(value = "verify-name", notes = "VERIFY_PROCESS_DEFINITION_NAME_NOTES")
  @ApiImplicitParams({
      @ApiImplicitParam(name = "name", value = "PROCESS_DEFINITION_NAME", required = true, dataTypeClass = String.class),
      @ApiImplicitParam(name = "code", value = "PROCESS_DEFINITION_CODE", required = false, dataTypeClass = Long.class),
  })
  @GetMapping(value = "/verify-name")
  @ResponseStatus(HttpStatus.OK)
  @ApiException(VERIFY_PROCESS_DEFINITION_NAME_UNIQUE_ERROR)
  @AccessLogAnnotation(ignoreRequestArgs = "loginUser")
  public Result verifyProcessDefinitionName(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
                                            @ApiParam(name = "projectCode", value = "PROJECT_CODE", required = true) @PathVariable long projectCode,
                                            @RequestParam(value = "name", required = true) String name,
                                            @RequestParam(value = "code", required = false, defaultValue = "0") long processDefinitionCode) {
    Map<String, Object> result = processDefinitionService.verifyProcessDefinitionName(loginUser, projectCode, name, processDefinitionCode);
    return returnDataList(result);
  }

  /**
   * 更新流程，包括流程定义、任务定义、流程任务关系、位置信息
   *
   * @param loginUser          login user
   * @param projectCode        project code
   * @param name               process definition name
   * @param code               process definition code
   * @param description        description
   * @param globalParams       globalParams
   * @param locations          locations for nodes
   * @param timeout            timeout
   * @param tenantCode         tenantCode
   * @param taskRelationJson   relation json for nodes
   * @param taskDefinitionJson taskDefinitionJson
   * @param otherParamsJson    otherParamsJson handle other params
   * @return update result code
   */
  @ApiOperation(value = "update", notes = "UPDATE_PROCESS_DEFINITION_NOTES")
  @ApiImplicitParams({
      @ApiImplicitParam(name = "name", value = "PROCESS_DEFINITION_NAME", required = true, dataTypeClass = String.class),
      @ApiImplicitParam(name = "code", value = "PROCESS_DEFINITION_CODE", required = true, dataTypeClass = long.class, example = "123456789"),
      @ApiImplicitParam(name = "locations", value = "PROCESS_DEFINITION_LOCATIONS", required = true, dataTypeClass = String.class),
      @ApiImplicitParam(name = "description", value = "PROCESS_DEFINITION_DESC", required = false, dataTypeClass = String.class),
      @ApiImplicitParam(name = "releaseState", value = "RELEASE_PROCESS_DEFINITION_NOTES", required = false, dataTypeClass = ReleaseState.class),
      @ApiImplicitParam(name = "otherParamsJson", value = "OTHER_PARAMS_JSON", required = false, dataTypeClass = String.class)
  })
  @PutMapping(value = "/{code}")
  @ResponseStatus(HttpStatus.OK)
  @ApiException(UPDATE_PROCESS_DEFINITION_ERROR)
  @AccessLogAnnotation(ignoreRequestArgs = "loginUser")
  public Result updateProcessDefinition(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
                                        @ApiParam(name = "projectCode", value = "PROJECT_CODE", required = true) @PathVariable long projectCode,
                                        @RequestParam(value = "name", required = true) String name,
                                        @PathVariable(value = "code", required = true) long code,
                                        @RequestParam(value = "description", required = false) String description,
                                        @RequestParam(value = "globalParams", required = false, defaultValue = "[]") String globalParams,
                                        @RequestParam(value = "locations", required = false) String locations,
                                        @RequestParam(value = "timeout", required = false, defaultValue = "0") int timeout,
                                        @RequestParam(value = "tenantCode", required = true) String tenantCode,
                                        @RequestParam(value = "taskRelationJson", required = true) String taskRelationJson,
                                        @RequestParam(value = "taskDefinitionJson", required = true) String taskDefinitionJson,
                                        @RequestParam(value = "otherParamsJson", required = false) String otherParamsJson,
                                        @RequestParam(value = "executionType", defaultValue = "PARALLEL") ProcessExecutionTypeEnum executionType,
                                        @RequestParam(value = "releaseState", required = false, defaultValue = "OFFLINE") ReleaseState releaseState) {

    Map<String, Object> result = processDefinitionService.updateProcessDefinition(loginUser, projectCode, name,
        code, description, globalParams,
        locations, timeout, tenantCode, taskRelationJson, taskDefinitionJson, otherParamsJson, executionType);
    // If the update fails, the result will be returned directly
    if (result.get(Constants.STATUS) != Status.SUCCESS) {
      return returnDataList(result);
    }

    // Judge whether to go online after editing,0 means offline, 1 means online
    if (releaseState == ReleaseState.ONLINE) {
      result = processDefinitionService.releaseProcessDefinition(loginUser, projectCode, code, releaseState);
    }
    return returnDataList(result);
  }

  /**
   * query process definition version paging list info
   * 查询版本信息，从ProcessDefinitionLog分页查询，version字段倒序
   *
   * @param loginUser   login user info
   * @param projectCode project code
   * @param pageNo      the process definition version list current page number
   * @param pageSize    the process definition version list page size
   * @param code        the process definition code
   * @return the process definition version list
   */
  @ApiOperation(value = "queryVersions", notes = "QUERY_PROCESS_DEFINITION_VERSIONS_NOTES")
  @ApiImplicitParams({
      @ApiImplicitParam(name = "pageNo", value = "PAGE_NO", required = true, dataTypeClass = int.class, example = "1"),
      @ApiImplicitParam(name = "pageSize", value = "PAGE_SIZE", required = true, dataTypeClass = int.class, example = "10"),
      @ApiImplicitParam(name = "code", value = "PROCESS_DEFINITION_CODE", required = true, dataTypeClass = long.class, example = "1")
  })
  @GetMapping(value = "/{code}/versions")
  @ResponseStatus(HttpStatus.OK)
  @ApiException(QUERY_PROCESS_DEFINITION_VERSIONS_ERROR)
  @AccessLogAnnotation(ignoreRequestArgs = "loginUser")
  public Result queryProcessDefinitionVersions(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
                                               @ApiParam(name = "projectCode", value = "PROJECT_CODE", required = true) @PathVariable long projectCode,
                                               @RequestParam(value = "pageNo") int pageNo,
                                               @RequestParam(value = "pageSize") int pageSize,
                                               @PathVariable(value = "code") long code) {

    Result result = checkPageParams(pageNo, pageSize);
    if (!result.checkResult()) {
      return result;
    }
    result = processDefinitionService.queryProcessDefinitionVersions(loginUser, projectCode, pageNo, pageSize, code);
    return result;
  }

  /**
   * switch certain process definition version
   * 流程定义回滚到前面的版本，这里LOG最新的版本3，回滚版本后，process、task、relation的版本可能成为了2
   *
   * @param loginUser   login user info
   * @param projectCode project code
   * @param code        the process definition code
   * @param version     the version user want to switch
   * @return switch version result code
   */
  @ApiOperation(value = "switchVersion", notes = "SWITCH_PROCESS_DEFINITION_VERSION_NOTES")
  @ApiImplicitParams({
      @ApiImplicitParam(name = "code", value = "PROCESS_DEFINITION_CODE", required = true, dataTypeClass = long.class, example = "1"),
      @ApiImplicitParam(name = "version", value = "VERSION", required = true, dataTypeClass = int.class, example = "100")
  })
  @GetMapping(value = "/{code}/versions/{version}")
  @ResponseStatus(HttpStatus.OK)
  @ApiException(SWITCH_PROCESS_DEFINITION_VERSION_ERROR)
  @AccessLogAnnotation(ignoreRequestArgs = "loginUser")
  public Result switchProcessDefinitionVersion(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
                                               @ApiParam(name = "projectCode", value = "PROJECT_CODE", required = true) @PathVariable long projectCode,
                                               @PathVariable(value = "code") long code,
                                               @PathVariable(value = "version") int version) {
    Map<String, Object> result =
        processDefinitionService.switchProcessDefinitionVersion(loginUser, projectCode, code, version);
    return returnDataList(result);
  }

  /**
   * delete the certain process definition version by version and process definition code
   * processCode对应的未使用到的历史版本删除，全部从LOG表中删除
   *
   * @param loginUser   login user info
   * @param projectCode project code
   * @param code        the process definition code
   * @param version     the process definition version user want to delete
   * @return delete version result code
   */
  @ApiOperation(value = "deleteVersion", notes = "DELETE_PROCESS_DEFINITION_VERSION_NOTES")
  @ApiImplicitParams({
      @ApiImplicitParam(name = "code", value = "PROCESS_DEFINITION_CODE", required = true, dataTypeClass = long.class, example = "1"),
      @ApiImplicitParam(name = "version", value = "VERSION", required = true, dataTypeClass = int.class, example = "100")
  })
  @DeleteMapping(value = "/{code}/versions/{version}")
  @ResponseStatus(HttpStatus.OK)
  @ApiException(DELETE_PROCESS_DEFINITION_VERSION_ERROR)
  @AccessLogAnnotation(ignoreRequestArgs = "loginUser")
  public Result deleteProcessDefinitionVersion(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
                                               @ApiParam(name = "projectCode", value = "PROJECT_CODE", required = true) @PathVariable long projectCode,
                                               @PathVariable(value = "code") long code,
                                               @PathVariable(value = "version") int version) {
    Map<String, Object> result =
        processDefinitionService.deleteProcessDefinitionVersion(loginUser, projectCode, code, version);
    return returnDataList(result);
  }

  /**
   * release process definition
   * 流程上线下线，上线更新流程状态，下线更新流程状态、同时需要下线任务调度
   *
   * @param loginUser    login user
   * @param projectCode  project code
   * @param code         process definition code
   * @param releaseState release state
   * @return release result code
   */
  @ApiOperation(value = "release", notes = "RELEASE_PROCESS_DEFINITION_NOTES")
  @ApiImplicitParams({
      @ApiImplicitParam(name = "name", value = "PROCESS_DEFINITION_NAME", required = true, dataTypeClass = String.class),
      @ApiImplicitParam(name = "code", value = "PROCESS_DEFINITION_CODE", required = true, dataTypeClass = long.class, example = "123456789"),
      @ApiImplicitParam(name = "releaseState", value = "PROCESS_DEFINITION_RELEASE", required = true, dataTypeClass = ReleaseState.class),
  })
  @PostMapping(value = "/{code}/release")
  @ResponseStatus(HttpStatus.OK)
  @ApiException(RELEASE_PROCESS_DEFINITION_ERROR)
  @AccessLogAnnotation(ignoreRequestArgs = "loginUser")
  public Result releaseProcessDefinition(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
                                         @ApiParam(name = "projectCode", value = "PROJECT_CODE", required = true) @PathVariable long projectCode,
                                         @PathVariable(value = "code", required = true) long code,
                                         @RequestParam(value = "releaseState", required = true) ReleaseState releaseState) {
    Map<String, Object> result =
        processDefinitionService.releaseProcessDefinition(loginUser, projectCode, code, releaseState);
    return returnDataList(result);
  }

  /**
   * 查询流程定义详情 返回 -> 流程定义、任务定义列表、流程任务关系列表
   *
   * @param loginUser   login user
   * @param projectCode project code
   * @param code        process definition code
   * @return process definition detail
   */
  @ApiOperation(value = "queryProcessDefinitionByCode", notes = "QUERY_PROCESS_DEFINITION_BY_CODE_NOTES")
  @ApiImplicitParams({
      @ApiImplicitParam(name = "code", value = "PROCESS_DEFINITION_CODE", required = true, dataTypeClass = long.class, example = "123456789")
  })
  @GetMapping(value = "/{code}")
  @ResponseStatus(HttpStatus.OK)
  @ApiException(QUERY_DETAIL_OF_PROCESS_DEFINITION_ERROR)
  @AccessLogAnnotation(ignoreRequestArgs = "loginUser")
  public Result queryProcessDefinitionByCode(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
                                             @ApiParam(name = "projectCode", value = "PROJECT_CODE", required = true) @PathVariable long projectCode,
                                             @PathVariable(value = "code", required = true) long code) {
    Map<String, Object> result =
        processDefinitionService.queryProcessDefinitionByCode(loginUser, projectCode, code);
    return returnDataList(result);
  }

  /**
   * query detail of process definition by name
   * 通过projectCode-name，查询项目下流程定义详情
   *
   * @param loginUser   login user
   * @param projectCode project code
   * @param name        process definition name
   * @return process definition detail
   */
  @ApiOperation(value = "queryProcessDefinitionByName", notes = "QUERY_PROCESS_DEFINITION_BY_NAME_NOTES")
  @ApiImplicitParams({
      @ApiImplicitParam(name = "name", value = "PROCESS_DEFINITION_NAME", required = true, dataTypeClass = String.class)
  })
  @GetMapping(value = "/query-by-name")
  @ResponseStatus(HttpStatus.OK)
  @ApiException(QUERY_DETAIL_OF_PROCESS_DEFINITION_ERROR)
  @AccessLogAnnotation(ignoreRequestArgs = "loginUser")
  public Result<ProcessDefinition> queryProcessDefinitionByName(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
                                                                @ApiParam(name = "projectCode", value = "PROJECT_CODE", required = true) @PathVariable long projectCode,
                                                                @RequestParam("name") String name) {
    Map<String, Object> result =
        processDefinitionService.queryProcessDefinitionByName(loginUser, projectCode, name);
    return returnDataList(result);
  }

  /**
   * query Process definition list
   * 查询项目下所有的流程定义详情
   *
   * @param loginUser   login user
   * @param projectCode project code
   * @return process definition list
   */
  @ApiOperation(value = "queryList", notes = "QUERY_PROCESS_DEFINITION_LIST_NOTES")
  @GetMapping(value = "/list")
  @ResponseStatus(HttpStatus.OK)
  @ApiException(QUERY_PROCESS_DEFINITION_LIST)
  @AccessLogAnnotation(ignoreRequestArgs = "loginUser")
  public Result queryProcessDefinitionList(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
                                           @ApiParam(name = "projectCode", value = "PROJECT_CODE", required = true) @PathVariable long projectCode) {
    Map<String, Object> result = processDefinitionService.queryProcessDefinitionList(loginUser, projectCode);
    return returnDataList(result);
  }

  /**
   * query Process definition simple list
   *
   * @param loginUser   login user
   * @param projectCode project code
   * @return process definition list
   */
  @ApiOperation(value = "querySimpleList", notes = "QUERY_PROCESS_DEFINITION_SIMPLE_LIST_NOTES")
  @GetMapping(value = "/simple-list")
  @ResponseStatus(HttpStatus.OK)
  @ApiException(QUERY_PROCESS_DEFINITION_LIST)
  @AccessLogAnnotation(ignoreRequestArgs = "loginUser")
  public Result queryProcessDefinitionSimpleList(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
                                                 @ApiParam(name = "projectCode", value = "PROJECT_CODE", required = true) @PathVariable long projectCode) {
    Map<String, Object> result = processDefinitionService.queryProcessDefinitionSimpleList(loginUser, projectCode);
    return returnDataList(result);
  }

  /**
   * 项目管理 -> 工作流定义 -> 分页检索查询
   *
   * @param loginUser       login user
   * @param projectCode     project code
   * @param searchVal       search value
   * @param otherParamsJson otherParamsJson handle other params
   * @param pageNo          page number
   * @param pageSize        page size
   * @param userId          user id
   * @return process definition page
   */
  @ApiOperation(value = "queryListPaging", notes = "QUERY_PROCESS_DEFINITION_LIST_PAGING_NOTES")
  @ApiImplicitParams({
      @ApiImplicitParam(name = "searchVal", value = "SEARCH_VAL", required = false, dataTypeClass = String.class),
      @ApiImplicitParam(name = "userId", value = "USER_ID", required = false, dataTypeClass = int.class, example = "100"),
      @ApiImplicitParam(name = "pageNo", value = "PAGE_NO", required = true, dataTypeClass = int.class, example = "1"),
      @ApiImplicitParam(name = "pageSize", value = "PAGE_SIZE", required = true, dataTypeClass = int.class, example = "10"),
      @ApiImplicitParam(name = "otherParamsJson", value = "OTHER_PARAMS_JSON", required = false, dataTypeClass = String.class)
  })
  @GetMapping()
  @ResponseStatus(HttpStatus.OK)
  @ApiException(QUERY_PROCESS_DEFINITION_LIST_PAGING_ERROR)
  @AccessLogAnnotation(ignoreRequestArgs = "loginUser")
  public Result<PageInfo<ProcessDefinition>> queryProcessDefinitionListPaging(
      @ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
      @ApiParam(name = "projectCode", value = "PROJECT_CODE", required = true) @PathVariable long projectCode,
      @RequestParam(value = "searchVal", required = false) String searchVal,
      @RequestParam(value = "otherParamsJson", required = false) String otherParamsJson,
      @RequestParam(value = "userId", required = false, defaultValue = "0") Integer userId,
      @RequestParam("pageNo") Integer pageNo,
      @RequestParam("pageSize") Integer pageSize) {

    Result<PageInfo<ProcessDefinition>> result = checkPageParams(pageNo, pageSize);
    if (!result.checkResult()) {
      return result;
    }
    searchVal = ParameterUtils.handleEscapes(searchVal);

    PageInfo<ProcessDefinition> pageInfo = processDefinitionService.queryProcessDefinitionListPaging(
        loginUser, projectCode, searchVal, otherParamsJson, userId, pageNo, pageSize);
    return Result.success(pageInfo);
  }

  /**
   * encapsulation tree view structure
   *
   * @param loginUser   login user
   * @param projectCode project code
   * @param code        process definition code
   * @param limit       limit
   * @return tree view json data
   */
  @ApiOperation(value = "viewTree", notes = "VIEW_TREE_NOTES")
  @ApiImplicitParams({
      @ApiImplicitParam(name = "code", value = "PROCESS_DEFINITION_CODE", required = true, dataTypeClass = long.class, example = "100"),
      @ApiImplicitParam(name = "limit", value = "LIMIT", required = true, dataTypeClass = int.class, example = "100")
  })
  @GetMapping(value = "/{code}/view-tree")
  @ResponseStatus(HttpStatus.OK)
  @ApiException(ENCAPSULATION_TREEVIEW_STRUCTURE_ERROR)
  @AccessLogAnnotation(ignoreRequestArgs = "loginUser")
  public Result viewTree(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
                         @ApiParam(name = "projectCode", value = "PROJECT_CODE", required = true) @PathVariable long projectCode,
                         @PathVariable("code") long code,
                         @RequestParam("limit") Integer limit) {
    Map<String, Object> result = processDefinitionService.viewTree(loginUser, projectCode, code, limit);
    return returnDataList(result);
  }

  /**
   * get tasks list by process definition code
   * 获取流程任务关系列表，取出preTaskCode和postTaskCode、t_ds_task_definition表in查询
   *
   * @param loginUser   login user
   * @param projectCode project code
   * @param code        process definition code
   * @return task list
   */
  @ApiOperation(value = "getTasksByDefinitionCode", notes = "GET_TASK_LIST_BY_DEFINITION_CODE_NOTES")
  @ApiImplicitParams({
      @ApiImplicitParam(name = "code", value = "PROCESS_DEFINITION_CODE", required = true, dataTypeClass = long.class, example = "100")
  })
  @GetMapping(value = "/{code}/tasks")
  @ResponseStatus(HttpStatus.OK)
  @ApiException(GET_TASKS_LIST_BY_PROCESS_DEFINITION_ID_ERROR)
  public Result getNodeListByDefinitionCode(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
                                            @ApiParam(name = "projectCode", value = "PROJECT_CODE", required = true) @PathVariable long projectCode,
                                            @PathVariable("code") long code) {
    Map<String, Object> result =
        processDefinitionService.getTaskNodeListByDefinitionCode(loginUser, projectCode, code);
    return returnDataList(result);
  }

  /**
   * get tasks list map by process definition multiple code
   * 获取多个流程的任务节点列表，返回值 Map<processCode, List<TaskDefinition>>
   *
   * @param loginUser   login user
   * @param projectCode project code
   * @param codes       process definition codes
   * @return node list data
   */
  @ApiOperation(value = "getTaskListByDefinitionCodes", notes = "GET_TASK_LIST_BY_DEFINITION_CODE_NOTES")
  @ApiImplicitParams({
      @ApiImplicitParam(name = "codes", value = "PROCESS_DEFINITION_CODES", required = true, dataTypeClass = String.class, example = "100,200,300")
  })
  @GetMapping(value = "/batch-query-tasks")
  @ResponseStatus(HttpStatus.OK)
  @ApiException(GET_TASKS_LIST_BY_PROCESS_DEFINITION_ID_ERROR)
  public Result getNodeListMapByDefinitionCodes(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
                                                @ApiParam(name = "projectCode", value = "PROJECT_CODE", required = true) @PathVariable long projectCode,
                                                @RequestParam("codes") String codes) {
    Map<String, Object> result =
        processDefinitionService.getNodeListMapByDefinitionCodes(loginUser, projectCode, codes);
    return returnDataList(result);
  }

  /**
   * get process definition list map by project code
   * 返回code、name、version，查询projectCode下面的流程列表
   *
   * @param loginUser   login user
   * @param projectCode project code
   * @return process definition list data
   */
  @ApiOperation(value = "getProcessListByProjectCode", notes = "GET_PROCESS_LIST_BY_PROCESS_CODE_NOTES")
  @ApiImplicitParams({
      @ApiImplicitParam(name = "projectCode", value = "PROJECT_CODE", required = true, dataTypeClass = long.class, example = "100")
  })
  @GetMapping(value = "/query-process-definition-list")
  @ResponseStatus(HttpStatus.OK)
  @ApiException(GET_TASKS_LIST_BY_PROCESS_DEFINITION_ID_ERROR)
  public Result getProcessListByProjectCodes(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
                                             @ApiParam(name = "projectCode", value = "PROJECT_CODE", required = true) @PathVariable long projectCode) {
    Map<String, Object> result = processDefinitionService.queryProcessDefinitionListByProjectCode(projectCode);
    return returnDataList(result);
  }

  /**
   * get task definition list by process definition code
   * 通过ProcessCode查询任务节点列表，返回任务简写信息
   *
   * @param loginUser   login user
   * @param projectCode project code
   * @return process definition list data
   */
  @ApiOperation(value = "getTaskListByProcessDefinitionCode", notes = "GET_TASK_LIST_BY_PROCESS_CODE_NOTES")
  @ApiImplicitParams({
      @ApiImplicitParam(name = "projectCode", value = "PROJECT_CODE", required = true, dataTypeClass = long.class, example = "100"),
      @ApiImplicitParam(name = "processDefinitionCode", value = "PROCESS_DEFINITION_CODE", required = true, dataTypeClass = long.class, example = "100"),
  })
  @GetMapping(value = "/query-task-definition-list")
  @ResponseStatus(HttpStatus.OK)
  @ApiException(GET_TASKS_LIST_BY_PROCESS_DEFINITION_ID_ERROR)
  public Result getTaskListByProcessDefinitionCode(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
                                                   @ApiParam(name = "projectCode", value = "PROJECT_CODE", required = true) @PathVariable long projectCode,
                                                   @RequestParam(value = "processDefinitionCode") Long processDefinitionCode) {
    Map<String, Object> result = processDefinitionService
        .queryTaskDefinitionListByProcessDefinitionCode(projectCode, processDefinitionCode);
    return returnDataList(result);
  }

  /**
   * delete process definition by code
   * 删除流程定义条件
   * 1、定时任务不能online、流程不能online、流程实例不能在运行中
   * 2、满足上面条件直接删除流程、任务列表、流程任务关系
   * 3、这里任务没有任何校验，因为任务和流程绑定，可以直接删除。如果任务被其它流程的组件引用、则忽略、查询时展示taskCode而非taskName即可。
   * 4、单纯删除任务定义，检查上下游关系，然后更新流程、流程任务关系、删除任务。
   *
   * @param loginUser   login user
   * @param projectCode project code
   * @param code        process definition code
   * @return delete result code
   */
  @ApiOperation(value = "deleteByCode", notes = "DELETE_PROCESS_DEFINITION_BY_ID_NOTES")
  @ApiImplicitParams({
      @ApiImplicitParam(name = "code", value = "PROCESS_DEFINITION_CODE", dataTypeClass = int.class, example = "100")
  })
  @DeleteMapping(value = "/{code}")
  @ResponseStatus(HttpStatus.OK)
  @ApiException(DELETE_PROCESS_DEFINE_BY_CODE_ERROR)
  @AccessLogAnnotation(ignoreRequestArgs = "loginUser")
  public Result deleteProcessDefinitionByCode(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
                                              @ApiParam(name = "projectCode", value = "PROJECT_CODE", required = true) @PathVariable long projectCode,
                                              @PathVariable("code") long code) {
    Map<String, Object> result =
        processDefinitionService.deleteProcessDefinitionByCode(loginUser, projectCode, code);
    return returnDataList(result);
  }

  /**
   * batch delete process definition by codes
   * 查询processCodes对应的流程列表，挨个删除流程
   *
   * @param loginUser   login user
   * @param projectCode project code
   * @param codes       process definition code list
   * @return delete result code
   */
  @ApiOperation(value = "batchDeleteByCodes", notes = "BATCH_DELETE_PROCESS_DEFINITION_BY_IDS_NOTES")
  @ApiImplicitParams({
      @ApiImplicitParam(name = "codes", value = "PROCESS_DEFINITION_CODE", required = true, dataTypeClass = String.class)
  })
  @PostMapping(value = "/batch-delete")
  @ResponseStatus(HttpStatus.OK)
  @ApiException(BATCH_DELETE_PROCESS_DEFINE_BY_CODES_ERROR)
  @AccessLogAnnotation(ignoreRequestArgs = "loginUser")
  public Result batchDeleteProcessDefinitionByCodes(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
                                                    @ApiParam(name = "projectCode", value = "PROJECT_CODE", required = true) @PathVariable long projectCode,
                                                    @RequestParam("codes") String codes) {
    Map<String, Object> result = new HashMap<>();
    Set<String> deleteFailedCodeSet = new HashSet<>();
    if (!StringUtils.isEmpty(codes)) {
      String[] processDefinitionCodeArray = codes.split(",");
      for (String strProcessDefinitionCode : processDefinitionCodeArray) {
        long code = Long.parseLong(strProcessDefinitionCode);
        try {
          Map<String, Object> deleteResult =
              processDefinitionService.deleteProcessDefinitionByCode(loginUser, projectCode, code);
          if (!Status.SUCCESS.equals(deleteResult.get(Constants.STATUS))) {
            deleteFailedCodeSet.add((String) deleteResult.get(Constants.MSG));
            logger.error((String) deleteResult.get(Constants.MSG));
          }
        } catch (Exception e) {
          deleteFailedCodeSet.add(MessageFormat.format(Status.DELETE_PROCESS_DEFINE_BY_CODES_ERROR.getMsg(),
              strProcessDefinitionCode));
        }
      }
    }

    if (!deleteFailedCodeSet.isEmpty()) {
      putMsg(result, BATCH_DELETE_PROCESS_DEFINE_BY_CODES_ERROR, String.join("\n", deleteFailedCodeSet));
    } else {
      putMsg(result, Status.SUCCESS);
    }
    return returnDataList(result);
  }

  /**
   * batch export process definition by codes
   * 查询List<DagDataSchedule> 然后写入Response
   *
   * @param loginUser   login user
   * @param projectCode project code
   * @param codes       process definition codes
   * @param response    response
   */
  @ApiOperation(value = "batchExportByCodes", notes = "BATCH_EXPORT_PROCESS_DEFINITION_BY_CODES_NOTES")
  @ApiImplicitParams({
      @ApiImplicitParam(name = "codes", value = "PROCESS_DEFINITION_CODE", required = true, dataTypeClass = String.class)
  })
  @PostMapping(value = "/batch-export")
  @ResponseBody
  @AccessLogAnnotation(ignoreRequestArgs = {"loginUser", "response"})
  public void batchExportProcessDefinitionByCodes(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
                                                  @ApiParam(name = "projectCode", value = "PROJECT_CODE", required = true) @PathVariable long projectCode,
                                                  @RequestParam("codes") String codes,
                                                  HttpServletResponse response) {
    try {
      processDefinitionService.batchExportProcessDefinitionByCodes(loginUser, projectCode, codes, response);
    } catch (Exception e) {
      logger.error(Status.BATCH_EXPORT_PROCESS_DEFINE_BY_IDS_ERROR.getMsg(), e);
    }
  }

  /**
   * query all process definition by project code
   * 查询流程定义列表，返回List<DagData>
   * DagData = ProcessDefinition、List<ProcessDefinitionRelationLog>、List<TaskDefinitionLog>
   *
   * @param loginUser   login user
   * @param projectCode project code
   * @return process definition list
   */
  @ApiOperation(value = "queryAllByProjectCode", notes = "QUERY_PROCESS_DEFINITION_All_BY_PROJECT_CODE_NOTES")
  @GetMapping(value = "/all")
  @ResponseStatus(HttpStatus.OK)
  @ApiException(QUERY_PROCESS_DEFINITION_LIST)
  @AccessLogAnnotation(ignoreRequestArgs = "loginUser")
  public Result queryAllProcessDefinitionByProjectCode(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
                                                       @ApiParam(name = "projectCode", value = "PROJECT_CODE", required = true) @PathVariable long projectCode) {
    Map<String, Object> result =
        processDefinitionService.queryAllProcessDefinitionByProjectCode(loginUser, projectCode);
    return returnDataList(result);
  }

  /**
   * import process definition
   * 流程定义导入，四要素：流程、任务、关系、定时任务
   *
   * @param loginUser   login user
   * @param projectCode project code
   * @param file        resource file
   * @return import result code
   */
  @ApiOperation(value = "importProcessDefinition", notes = "IMPORT_PROCESS_DEFINITION_NOTES")
  @ApiImplicitParams({
      @ApiImplicitParam(name = "file", value = "RESOURCE_FILE", required = true, dataTypeClass = MultipartFile.class)
  })
  @PostMapping(value = "/import")
  @ApiException(IMPORT_PROCESS_DEFINE_ERROR)
  @AccessLogAnnotation(ignoreRequestArgs = {"loginUser", "file"})
  public Result importProcessDefinition(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
                                        @ApiParam(name = "projectCode", value = "PROJECT_CODE", required = true) @PathVariable long projectCode,
                                        @RequestParam("file") MultipartFile file) {
    Map<String, Object> result;
    if ("application/zip".equals(file.getContentType())) {
      result = processDefinitionService.importSqlProcessDefinition(loginUser, projectCode, file);
    } else {
      result = processDefinitionService.importProcessDefinition(loginUser, projectCode, file);
    }
    return returnDataList(result);
  }

  /**
   * create empty process definition
   *
   * @param loginUser    login user
   * @param projectCode  project code
   * @param name         process definition name
   * @param description  description
   * @param globalParams globalParams
   * @param timeout      timeout
   * @param tenantCode   tenantCode
   * @param scheduleJson scheduleJson
   * @return process definition code
   */
  @ApiOperation(value = "createEmptyProcessDefinition", notes = "CREATE_EMPTY_PROCESS_NOTES")
  @ApiImplicitParams({
      @ApiImplicitParam(name = "name", value = "PROCESS_DEFINITION_NAME", required = true, dataTypeClass = String.class),
      @ApiImplicitParam(name = "projectCode", value = "PROJECT_CODE", required = true, dataTypeClass = long.class, example = "123456789"),
      @ApiImplicitParam(name = "description", value = "PROCESS_DEFINITION_DESC", required = false, dataTypeClass = String.class)
  })
  @PostMapping(value = "/empty")
  @ResponseStatus(HttpStatus.OK)
  @ApiException(CREATE_PROCESS_DEFINITION_ERROR)
  @AccessLogAnnotation(ignoreRequestArgs = "loginUser")
  public Result createEmptyProcessDefinition(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
                                             @ApiParam(name = "projectCode", value = "PROJECT_CODE", required = true) @PathVariable long projectCode,
                                             @RequestParam(value = "name", required = true) String name,
                                             @RequestParam(value = "description", required = false) String description,
                                             @RequestParam(value = "globalParams", required = false, defaultValue = "[]") String globalParams,
                                             @RequestParam(value = "timeout", required = false, defaultValue = "0") int timeout,
                                             @RequestParam(value = "tenantCode", required = true) String tenantCode,
                                             @RequestParam(value = "scheduleJson", required = false) String scheduleJson,
                                             @RequestParam(value = "executionType", defaultValue = "PARALLEL") ProcessExecutionTypeEnum executionType) {
    return returnDataList(processDefinitionService.createEmptyProcessDefinition(loginUser, projectCode, name,
        description, globalParams,
        timeout, tenantCode, scheduleJson, executionType));
  }

  /**
   * update process definition basic info, not including task definition, task relation and location.
   * 更新流程的基本信息，包括定时任务信息
   *
   * @param loginUser       login user
   * @param projectCode     project code
   * @param name            process definition name
   * @param code            process definition code
   * @param description     description
   * @param globalParams    globalParams
   * @param timeout         timeout
   * @param tenantCode      tenantCode
   * @param scheduleJson    scheduleJson
   * @param executionType   executionType
   * @param releaseState    releaseState
   * @param otherParamsJson otherParamsJson handle other params
   * @return update result code
   */
  @ApiOperation(value = "updateBasicInfo", notes = "UPDATE_PROCESS_DEFINITION_BASIC_INFO_NOTES")
  @ApiImplicitParams({
      @ApiImplicitParam(name = "name", value = "PROCESS_DEFINITION_NAME", required = true, dataTypeClass = String.class),
      @ApiImplicitParam(name = "code", value = "PROCESS_DEFINITION_CODE", required = true, dataTypeClass = long.class, example = "123456789"),
      @ApiImplicitParam(name = "description", value = "PROCESS_DEFINITION_DESC", required = false, dataTypeClass = String.class),
      @ApiImplicitParam(name = "releaseState", value = "RELEASE_PROCESS_DEFINITION_NOTES", required = false, dataTypeClass = ReleaseState.class),
      @ApiImplicitParam(name = "otherParamsJson", value = "OTHER_PARAMS_JSON", required = false, dataTypeClass = String.class)
  })
  @PutMapping(value = "/{code}/basic-info")
  @ResponseStatus(HttpStatus.OK)
  @ApiException(UPDATE_PROCESS_DEFINITION_ERROR)
  @AccessLogAnnotation(ignoreRequestArgs = "loginUser")
  public Result updateProcessDefinitionBasicInfo(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
                                                 @ApiParam(name = "projectCode", value = "PROJECT_CODE", required = true) @PathVariable long projectCode,
                                                 @RequestParam(value = "name", required = true) String name,
                                                 @PathVariable(value = "code", required = true) long code,
                                                 @RequestParam(value = "description", required = false) String description,
                                                 @RequestParam(value = "globalParams", required = false, defaultValue = "[]") String globalParams,
                                                 @RequestParam(value = "timeout", required = false, defaultValue = "0") int timeout,
                                                 @RequestParam(value = "tenantCode", required = true) String tenantCode,
                                                 @RequestParam(value = "scheduleJson", required = false) String scheduleJson,
                                                 @RequestParam(value = "otherParamsJson", required = false) String otherParamsJson,
                                                 @RequestParam(value = "executionType", defaultValue = "PARALLEL") ProcessExecutionTypeEnum executionType,
                                                 @RequestParam(value = "releaseState", required = false, defaultValue = "OFFLINE") ReleaseState releaseState) {
    Map<String, Object> result = processDefinitionService.updateProcessDefinitionBasicInfo(loginUser, projectCode,
        name, code, description, globalParams,
        timeout, tenantCode, scheduleJson, otherParamsJson, executionType);
    // If the update fails, the result will be returned directly
    if (result.get(Constants.STATUS) != Status.SUCCESS) {
      return returnDataList(result);
    }

    // Judge whether to go online after editing,0 means offline, 1 means online
    if (releaseState == ReleaseState.ONLINE) {
      result = processDefinitionService.releaseWorkflowAndSchedule(loginUser, projectCode, code, releaseState);
    }
    return returnDataList(result);
  }

  /**
   * release process definition and schedule
   * 流程和调度发版
   *
   * @param loginUser    login user
   * @param projectCode  project code
   * @param code         process definition code
   * @param releaseState releaseState
   * @return update result code
   */
  @ApiOperation(value = "releaseWorkflowAndSchedule", notes = "RELEASE_WORKFLOW_SCHEDULE_NOTES")
  @ApiImplicitParams({
      @ApiImplicitParam(name = "projectCode", value = "PROCESS_DEFINITION_NAME", required = true, dataTypeClass = long.class),
      @ApiImplicitParam(name = "code", value = "PROCESS_DEFINITION_CODE", required = true, dataTypeClass = long.class, example = "123456789"),
      @ApiImplicitParam(name = "releaseState", value = "RELEASE_PROCESS_DEFINITION_NOTES", required = true, dataTypeClass = ReleaseState.class)
  })
  @PostMapping(value = "/{code}/release-workflow")
  @ResponseStatus(HttpStatus.OK)
  @ApiException(RELEASE_PROCESS_DEFINITION_ERROR)
  @AccessLogAnnotation(ignoreRequestArgs = "loginUser")
  public Result releaseWorkflowAndSchedule(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
                                           @ApiParam(name = "projectCode", value = "PROJECT_CODE", required = true) @PathVariable long projectCode,
                                           @PathVariable(value = "code", required = true) long code,
                                           @RequestParam(value = "releaseState", required = true, defaultValue = "OFFLINE") ReleaseState releaseState) {
    return returnDataList(
        processDefinitionService.releaseWorkflowAndSchedule(loginUser, projectCode, code, releaseState));
  }

  /**
   * query process definition global variables and local variables
   *
   * @param loginUser login user
   * @param code      process definition code
   * @return variables data
   */
  @Operation(summary = "viewVariables", description = "QUERY_PROCESS_DEFINITION_GLOBAL_VARIABLES_AND_LOCAL_VARIABLES_NOTES")
  @Parameters({
      @Parameter(name = "code", description = "PROCESS_DEFINITION_CODE", required = true, schema = @Schema(implementation = long.class, example = "100"))
  })
  @GetMapping(value = "/{code}/view-variables")
  @ResponseStatus(HttpStatus.OK)
  @ApiException(QUERY_PROCESS_DEFINITION_ALL_VARIABLES_ERROR)
  @AccessLogAnnotation
  public Result viewVariables(@Parameter(hidden = true) @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
                              @Parameter(name = "projectCode", description = "PROJECT_CODE", required = true) @PathVariable long projectCode,
                              @PathVariable("code") Long code) {
    Map<String, Object> result = processDefinitionService.viewVariables(loginUser, projectCode, code);
    return returnDataList(result);
  }

}
